package chapter5;

import lombok.extern.slf4j.Slf4j;

import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * @author caiya
 * @date 2020/3/26 20:59
 */
@Slf4j
public class ConcurrentLinkedQueueTest {
    static final ConcurrentLinkedQueue<String> concurrentLinkedQueue = new ConcurrentLinkedQueue<>();
    /**
     * ConcurrentLinkedQueue：单向无界非阻塞队列，操作时直接返回，不会阻塞挂起当前线程
     * 1、ConcurrentLinkedQueue 实现原理
     *      底层使用单向无界链表，使用 cas 保证以下操作的原子性，节点内容使用 volatile 修饰保证内存可见性
     * 2、boolean offer(E e)：
     *      1）队尾插入
     *      2）元素 e 不能为空，否则 NPE
     *      3）通过无限循环进行 cas 尝试，所以会始终返回 true
     * 3、boolean add(E e)：底层使用 offer
     * 4、E poll()：
     *      1）队首获取并移除元素
     *      2）如果队列为空，则返回 null
     * 5、E peek()：
     *      1）队首获取但是不移除元素
     *      2）如果队列为空，则返回 null
     * 6、int size()：获取队列元素个数（慎用，不准确）
     *      1）size() 没有使用 cas，所以多线程下可能拿到的数值不准确
     * 7、boolean remove(Object o)：
     *      1）删除指定元素，如果存在多个，则仅删除第一个
     * 8、boolean contains(Object o)：判断队列是否包含指定元素（慎用，不准确）
     *      1）由于和 size() 一样，该操作时没有 cas，所以获取的数据不准确，存在线程安全问题
     */
    public static void main(String[] args) {
        // size为0的时候，poll为null
        log.debug("concurrentLinkedQueue.size(): {}", concurrentLinkedQueue.size());
        log.debug("concurrentLinkedQueue.poll(): {}", concurrentLinkedQueue.poll());

        concurrentLinkedQueue.offer("张三");
        concurrentLinkedQueue.offer("王五");
        concurrentLinkedQueue.offer("李四");
        concurrentLinkedQueue.offer("王五");

        log.debug("concurrentLinkedQueue.size(): {}", concurrentLinkedQueue.size());

        // poll获取队首元素后，size-1
        log.debug("concurrentLinkedQueue.poll(): {}", concurrentLinkedQueue.poll());
        log.debug("concurrentLinkedQueue.size(): {}", concurrentLinkedQueue.size());

        // peek获取队首元素后，size不变
        log.debug("concurrentLinkedQueue.peek(): {}", concurrentLinkedQueue.peek());
        log.debug("concurrentLinkedQueue.size(): {}", concurrentLinkedQueue.size());

        // 删除的元素有很多时，只会删除排在最前面的那个，并返回true
        log.debug("concurrentLinkedQueue.remove(): {}", concurrentLinkedQueue.remove("法斯特"));
        log.debug("concurrentLinkedQueue.remove(): {}", concurrentLinkedQueue.remove("王五"));
        log.debug("concurrentLinkedQueue.size(): {}", concurrentLinkedQueue.size());

        // remove只删除了一个 "王五"，所以contains返回true
        log.debug("concurrentLinkedQueue.contains(): {}", concurrentLinkedQueue.contains("王五"));

        Iterator<String> iterator = concurrentLinkedQueue.iterator();
        while (iterator.hasNext()) {
            String e = iterator.next();
            log.debug(e);
        }
    }
}
